/*
 * Copyright (C) 2016 JetRadar
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.jetradarmobile.snowfall;

import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.utils.Color;
import ohos.media.image.PixelMap;
import ohos.media.image.common.Size;

/**
 * 控制雪花XY轴及透明度的类
 *
 * @since 2021-05-24
 */
public class Snowflake {
    private int size = 0;
    private int alpha = 255;
    private PixelMap pixelMap = null;
    private double speedX = 0.0;
    private double speedY = 0.0;
    private double positionX = 0.0;
    private double positionY = 0.0;
    private boolean shouldRecycleFalling = true;
    private boolean stopped = false;
    private Randomizer randomizer;
    private Params params;
    private Paint _paint = null;
    private Paint paint;
    private PixelMapHolder holder;
    private PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();

    /**
     * Snowflake构造方法
     *
     * @param randomizer
     * @param params
     */
    public Snowflake(Randomizer randomizer, Params params) {
        this.randomizer = randomizer;
        this.params = params;
        initializationOptions.size = new Size();
        holder = new PixelMapHolder(params.image);
        reset(null);
    }

    /**
     * 获取画笔Paint
     *
     * @return Paint
     */
    public Paint getPaint() {
        if (_paint == null) {
            _paint = new Paint();
            _paint.color = Color.WHITE;
            _paint.setStyle(Paint.Style.FILL_STYLE);
            _paint.setAntiAlias(true);
        }
        return _paint;
    }

    /**
     * 重新设置雪花的位置
     *
     * @param positionY
     */
    public void reset(Double positionY) {
        shouldRecycleFalling = true;
        size = randomizer.randomInt(params.sizeMinInPx, params.sizeMaxInPx, true);
        if (params.image != null) {
            initializationOptions.size.width = size;
            initializationOptions.size.height = size;
            pixelMap = PixelMap.create(params.image, initializationOptions);
        }

        float speed = ((float) (size - params.sizeMinInPx) / (params.sizeMaxInPx - params.sizeMinInPx)
                * (params.speedMax - params.speedMin) + params.speedMin);
        double angle = Math.toRadians(randomizer.randomDouble(params.angleMax) * randomizer.randomSignum());
        speedX = speed * Math.sin(angle);
        speedY = speed * Math.cos(angle);

        alpha = randomizer.randomInt(params.alphaMin, params.alphaMax, false);
        getPaint().setAlpha(alpha / params.alphaMax);

        positionX = randomizer.randomDouble(params.parentWidth);
        if (positionY != null) {
            this.positionY = positionY;
        } else {
            this.positionY = randomizer.randomDouble(params.parentHeight);
            if (!params.alreadyFalling) {
                this.positionY = this.positionY - params.parentHeight - size;
            }
        }
    }

    public Boolean isStillFalling() {
        return (shouldRecycleFalling || (positionY > 0 && positionY < params.parentHeight));
    }

    /**
     * 控制雪花的XY轴
     */
    public void update() {
        if (positionY > params.parentHeight) {
            if (shouldRecycleFalling) {
                if (stopped) {
                    stopped = false;
                    reset(null);
                } else {
                    // 雪花走出屏幕  重新回到上方
                    reset((double) -size);
                }
            } else {
                positionY = params.parentHeight + (double) size;
                stopped = true;
            }
        }
        if (params.fadingEnabled) {
            getPaint().setAlpha((alpha * ((float) (params.parentHeight - positionY) / params.parentHeight)) / alpha);
        }
        positionX += speedX;
        positionY += speedY;
    }

    /**
     * 绘制图片
     *
     * @param canvas
     */
    public void draw(Canvas canvas) {
        if (pixelMap != null) {
            holder.resetPixelMap(pixelMap);
            canvas.drawPixelMapHolder(holder, (float) positionX, (float) positionY, getPaint());
        } else {
            canvas.drawCircle((float) positionX, (float) positionY, size, getPaint());
        }
    }

    public static class Params {
        int parentWidth;
        int parentHeight;
        PixelMap image;
        int alphaMin;
        int alphaMax;
        int angleMax;
        int sizeMinInPx;
        int sizeMaxInPx;
        int speedMin;
        int speedMax;
        boolean fadingEnabled;
        boolean alreadyFalling;

        /**
         * Params类的构造方法
         *
         * @param parentWidth
         * @param parentHeight
         * @param image
         * @param alphaMin
         * @param alphaMax
         * @param angleMax
         * @param sizeMinInPx
         * @param sizeMaxInPx
         * @param speedMin
         * @param speedMax
         * @param fadingEnabled
         * @param alreadyFalling
         */
        public Params(int parentWidth, int parentHeight, PixelMap image, int alphaMin, int alphaMax, int angleMax, int sizeMinInPx, int sizeMaxInPx, int speedMin, int speedMax, boolean fadingEnabled, boolean alreadyFalling) {
            this.parentWidth = parentWidth;
            this.parentHeight = parentHeight;
            this.image = image;
            this.alphaMin = alphaMin;
            this.alphaMax = alphaMax;
            this.angleMax = angleMax;
            this.sizeMinInPx = sizeMinInPx;
            this.sizeMaxInPx = sizeMaxInPx;
            this.speedMin = speedMin;
            this.speedMax = speedMax;
            this.fadingEnabled = fadingEnabled;
            this.alreadyFalling = alreadyFalling;
        }
    }
}
